package org.sauceggplant;

import javax.swing.*;
import java.io.File;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 解密
 *
 * @author jacob
 * @version 0.1
 */
public class Decrypt {

    private JProgressBar progressBar;

    public Decrypt(JProgressBar progressBar) {
        this.progressBar = progressBar;
    }

    /**
     * 解密
     *
     * @param file
     */
    public void decrypt(File file) {
        System.out.println("Decrypting file: " + file.getAbsolutePath());
        byte[] encryptData = FileUtil.file2bytes(file);
        byte[][] encryptDatas = ByteUtil.split(encryptData, 256);
        byte[][] decryptDatas = new byte[encryptDatas.length][];
        File priKeyFile = new File("key/PrivateKey.pem");
        if (!priKeyFile.exists()) {
            JOptionPane.showMessageDialog(null, "PrivateKey.pem证书文件不存在", "Error", JOptionPane.ERROR_MESSAGE);
            return;
        }
        byte[] privateKeyData = PemUtil.readPem(priKeyFile);
        PrivateKey privateKey = null;
        try {
            privateKey = KeyFactory.getInstance(PemUtil.ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(privateKeyData));
        } catch (InvalidKeySpecException e) {
            JOptionPane.showMessageDialog(null, "PrivateKey.pem证书无效", "Error", JOptionPane.ERROR_MESSAGE);
            return;
        } catch (NoSuchAlgorithmException e) {
            JOptionPane.showMessageDialog(null, "PrivateKey.pem证书算法错误", "Error", JOptionPane.ERROR_MESSAGE);
            return;
        }
        final CountDownLatch countDownLatch = new CountDownLatch(encryptDatas.length);
        FutureTask<byte[]>[] futureTasks = new FutureTask[encryptDatas.length];
        System.out.println("Decrypting block size: " + encryptDatas.length);
        progressBar.setMaximum(encryptDatas.length);
        new Thread(new Progress(progressBar, encryptDatas.length, countDownLatch)).start();
        for (int i = 0; i < encryptDatas.length; i++) {
            futureTasks[i] = new FutureTask<byte[]>(new Task(countDownLatch, privateKey, encryptDatas[i]));
            new Thread(futureTasks[i]).start();
        }
        try {
            countDownLatch.await();
            for (int i = 0; i < encryptDatas.length; i++) {
                decryptDatas[i] = futureTasks[i].get();
            }
            String path = file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - file.getName().length());
            File dFile = FileUtil.byteArray2file(decryptDatas, path + file.getName().substring(0, file.getName().length() - 6));
            System.out.println("Decrypted file: " + dFile.getAbsolutePath());
        } catch (InterruptedException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, "解密任务被中断，解密失败", "Error", JOptionPane.ERROR_MESSAGE);
        } catch (ExecutionException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, "解密失败", "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    static class Task implements Callable<byte[]> {
        private CountDownLatch countDownLatch;
        private PrivateKey privateKey;
        private byte[] encryptData;

        public Task(CountDownLatch countDownLatch, PrivateKey privateKey, byte[] encryptData) {
            this.countDownLatch = countDownLatch;
            this.privateKey = privateKey;
            this.encryptData = encryptData;
        }

        public byte[] call() {
            byte[] decryptData = null;
            try {
                decryptData = RSAUtil.decrypt(privateKey, encryptData);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                countDownLatch.countDown();
            }
            return decryptData;
        }
    }
}
